<?php
class PropSystem {
    private $redisManager;
    private $logger;
    private $config;

    public function __construct() {
        $this->redisManager = new RedisManager();
        $date = date('YmdHis');
        $this->logger = new Logger('logs/log'.$date.'.log');
        $this->config = new Config();
    }

    public function buyProp($playerId, $propType) {
        $props = $this->config->get('props');
        if (!isset($props[$propType])) {
            throw new Exception("道具不存在");
        }

        $playerCoins = $this->getPlayerCoins($playerId);
        $propPrice = $props[$propType]['price'];

        if ($playerCoins < $propPrice) {
            throw new Exception("金币不足");
        }

        // 扣除金币
        $this->updatePlayerCoins($playerId, -$propPrice);

        // 添加道具到玩家库存
        $inventory = $this->getPlayerInventory($playerId);
        if (!isset($inventory[$propType])) {
            $inventory[$propType] = 0;
        }
        $inventory[$propType]++;

        $this->redisManager->setGameData($playerId, 'inventory', $inventory);
        return true;
    }

    /**
     * 批量购买所有道具一次
     * @param string $playerId 玩家ID
     * @return bool 是否全部购买成功
     * @throws Exception 如果购买过程中出现异常
     */
    public function buyAllProps(string $playerId): bool {
        $props = $this->config->get('props');
        $this->logger->info("玩家 {$playerId} 开始批量购买所有道具");

        // 计算总金币消耗
        $totalCost = 0;
        foreach ($props as $type => $prop) {
            if (!isset($prop)) {
                $this->logger->error("道具 {$type} 不存在");
                throw new Exception("道具 {$type} 不存在");
            }
            $totalCost += $prop['price'];
        }

        $playerCoins = $this->getPlayerCoins($playerId);
        $this->logger->info("玩家 {$playerId} 当前金币: {$playerCoins}, 总消耗金币: {$totalCost}");

        // 检查金币是否足够
        if ($playerCoins < $totalCost) {
            $this->logger->error("玩家 {$playerId} 的金币不足，无法批量购买道具");
            throw new Exception("金币不足，无法批量购买道具");
        }

        // 扣除总金币
        $this->updatePlayerCoins($playerId, -$totalCost);
        $this->logger->info("玩家 {$playerId} 扣除金币 {$totalCost} 成功");

        // 更新道具库存
        $inventory = $this->getPlayerInventory($playerId);
        foreach ($props as $type => $prop) {
            try {
                $this->logger->info("开始处理道具 {$type} 的购买流程");

                if (!isset($inventory[$type])) {
                    $inventory[$type] = 0;
                }
                $inventory[$type]++;
                $this->logger->info("玩家 {$playerId} 的道具 {$type} 库存更新为: {$inventory[$type]}");
            } catch (Exception $e) {
                $this->logger->error("更新道具 {$type} 库存时发生异常: " . $e->getMessage());
                throw $e; // 抛出异常，由上层处理
            }
        }

        // 保存库存
        $this->redisManager->setGameData($playerId, 'inventory', $inventory);
        $this->logger->info("玩家 {$playerId} 批量购买所有道具完成");
        return true;
    }


    /**
     * 使用道具
     * @param string $gameId 牌局id
     * @param string $playerId 玩家id
     * @param string $propType 道具类型
     * @param array $params 参数
     * @return mixed
     * @throws Exception
     */
    public function useProp(string $gameId, string $playerId, string $propType, array $params = []): mixed
    {
        // 记录开始使用道具
        $this->logger->info("玩家 {$playerId} 开始使用道具 {$propType}，牌局ID: {$gameId}");

        try {
            // 获取游戏数据
            $gameData = $this->redisManager->getGameData($gameId, 'game_state');
            $this->logger->info("获取游戏数据成功: " . json_encode($gameData, JSON_UNESCAPED_UNICODE));

            // 获取玩家道具库存
            $inventory = $this->getPlayerInventory($playerId);
            $this->logger->info("玩家 {$playerId} 的道具库存: " . json_encode($inventory, JSON_UNESCAPED_UNICODE));

            // 检查道具数量是否足够
            if (!isset($inventory[$propType]) || $inventory[$propType] <= 0) {
                $this->logger->error("玩家 {$playerId} 的道具 {$propType} 数量不足");
                throw new Exception("道具数量不足");
            }

            // 应用道具效果
            $this->logger->info("开始应用道具 {$propType} 的效果");
            $result = $this->applyPropEffect($gameId, $propType, $params, $gameData);

            // 减少道具数量
            $inventory[$propType]--;
            $this->redisManager->setGameData($playerId, 'inventory', $inventory);
            $this->logger->info("道具 {$propType} 使用成功，剩余数量: {$inventory[$propType]}");

            // 记录道具使用结果
            $this->logger->info("道具 {$propType} 使用完成，结果: " . json_encode($result, JSON_UNESCAPED_UNICODE));

            return $result;
        } catch (Exception $e) {
            // 记录异常信息
            $this->logger->error("使用道具 {$propType} 时发生异常: " . $e->getMessage());
            throw $e; // 重新抛出异常，由上层处理
        }
    }

    /**
     * 道具效果应用
     * @param string $gameId
     * @param string $propType
     * @param array $params
     * @param array $gameData
     * @return array
     * @throws Exception
     */
    private function applyPropEffect(string $gameId, string $propType, array $params, array $gameData): array {
        $this->logger->info("开始应用道具 {$propType} 的效果，参数: " . json_encode($params, JSON_UNESCAPED_UNICODE));

        try {
            switch ($propType) {
                case 'card_point_boost':
                    // 指定牌点数加成
                    if (!isset($params['card_index'])) {
                        $this->logger->error("道具 {$propType} 缺少参数 card_index");
                        throw new Exception("缺少参数 card_index");
                    }
                    $index = $params['card_index'];
                    if (!isset($gameData['hand'][$index])) {
                        $this->logger->error("道具 {$propType} 指定的牌索引 {$index} 无效");
                        throw new Exception("牌索引无效");
                    }
                    $gameData['hand'][$index]['value'] *= 2;
                    $this->logger->info("道具 {$propType} 效果：牌索引 {$index} 的点数翻倍，新值: {$gameData['hand'][$index]['value']}");
                    break;

                case 'hand_multiplier':
                    // 给指定牌型增加倍率
                    if (!isset($params['hand_type'])) {
                        $this->logger->error("道具 {$propType} 缺少参数 hand_type");
                        throw new Exception("缺少参数 hand_type");
                    }
                    $index = $params['hand_type'];
                    $hand_types = $this->config->get('hand_types');
                    if (!in_array($index, array_keys($hand_types))) {
                        $this->logger->info("牌型数据：" . json_encode(array_keys($hand_types), JSON_UNESCAPED_UNICODE));
                        $this->logger->error("道具 {$propType} 指定的牌型 {$index} 无效");
                        throw new Exception("牌型无效");
                    }

                    $this->redisManager->setGameData($gameId, 'hand_type_multiplier', $index);
                    $this->logger->info("道具 {$propType} 效果：给指定牌型增加倍率");
                    break;

                case 'card_replacement':
                    // 指定牌替换
                    if (!isset($params['old_card_id']) || !isset($params['new_card_id'])) {
                        $this->logger->error("道具 {$propType} 缺少参数 old_card_id 或 new_card_id");
                        throw new Exception("缺少参数 old_card_id 或 new_card_id");
                    }
                    $deck = $this->redisManager->getGameData($gameId, 'deck');
                    $newCardIndex = null;
                    foreach ($deck as $index => $card) {
                        if ($card['id'] === $params['new_card_id']) {
                            $newCardIndex = $index;
                            break;
                        }
                    }
                    if ($newCardIndex === null) {
                        $this->logger->error("道具 {$propType} 指定的新牌 {$params['new_card_id']} 不在牌池中");
                        throw new Exception("新牌不在牌池中");
                    }
                    $newCard = $deck[$newCardIndex];
                    unset($deck[$newCardIndex]);
                    $deck = array_values($deck);

                    $oldCard = null;
                    foreach ($gameData['hand'] as &$card) {
                        if ($card['id'] === $params['old_card_id']) {
                            $oldCard = $card;
                            $card = $newCard;
                            $this->logger->info("道具 {$propType} 效果：牌 {$params['old_card_id']} 替换为 {$params['new_card_id']}");
                            break;
                        }
                    }
                    if ($oldCard === null) {
                        $this->logger->error("道具 {$propType} 指定的旧牌 {$params['old_card_id']} 不在手牌中");
                        throw new Exception("旧牌不在手牌中");
                    }

                    $deck[] = $oldCard;
                    $this->redisManager->setGameData($gameId, 'deck', $deck);
                    $this->logger->info("道具 {$propType} 效果：旧牌 {$params['old_card_id']} 已放回牌池");
                    break;

                case 'card_double':
                    // 单牌点数翻倍（随机选择一张手牌）
                    if (empty($gameData['hand'])) {
                        $this->logger->error("道具 {$propType} 无法使用：手牌为空");
                        throw new Exception("手牌为空");
                    }
                    $randomIndex = array_rand($gameData['hand']);
                    $gameData['hand'][$randomIndex]['value'] *= 2;
                    $this->logger->info("道具 {$propType} 效果：随机选择牌 {$gameData['hand'][$randomIndex]['id']} 点数翻倍，新值: {$gameData['hand'][$randomIndex]['value']}");
                    break;

                case 'suit_double':
                    // 花色点数加倍
                    if (!isset($params['suit'])) {
                        $this->logger->error("道具 {$propType} 缺少参数 suit");
                        throw new Exception("缺少参数 suit");
                    }
                    foreach ($gameData['hand'] as &$card) {
                        if ($card['suit'] === $params['suit']) {
                            $card['value'] *= 2;
                        }
                    }
                    $this->logger->info("道具 {$propType} 效果：花色 {$params['suit']} 的所有牌点数翻倍");
                    break;

                case 'extra_play':
                    // 增加出牌次数
                    $gameData['play_chances']++;
                    $this->logger->info("道具 {$propType} 效果：出牌次数+1，当前次数: {$gameData['play_chances']}");
                    break;

                case 'extra_discard':
                    // 增加弃牌次数
                    $gameData['discard_chances']++;
                    $this->logger->info("道具 {$propType} 效果：弃牌次数+1，当前次数: {$gameData['discard_chances']}");
                    break;

                case 'critical_strike':
                    // 设置暴击状态
                    $this->redisManager->setGameData($gameId, 'critical_strike', true);
                    $this->logger->info("道具 {$propType} 效果：暴击状态已激活");
                    break;

                default:
                    $this->logger->error("未知的道具类型: {$propType}");
                    throw new Exception("未知的道具类型");
            }

            // 更新游戏数据
            $this->redisManager->setGameData($gameId, 'game_state', $gameData);
            $this->logger->info("道具 {$propType} 效果应用完成，更新后的游戏数据: " . json_encode($gameData, JSON_UNESCAPED_UNICODE));

            return $gameData;
        } catch (Exception $e) {
            $this->logger->error("应用道具 {$propType} 效果时发生异常: " . $e->getMessage());
            throw $e;
        }
    }

    private function getPlayerCoins($playerId) {
        return $this->redisManager->getGameData($playerId, 'coins') ?? 0;
    }

    private function updatePlayerCoins($playerId, $amount) {
        $currentCoins = $this->getPlayerCoins($playerId);
        $this->redisManager->setGameData($playerId, 'coins', $currentCoins + $amount);
    }

    private function getPlayerInventory($playerId) {
        return $this->redisManager->getGameData($playerId, 'inventory') ?? [];
    }
}
?>